#include "Dwarf.Unmanaged.Mpi.h"

//Pointers to the factory functions.
static DLLParseArguments pDLLParseArguments;
static DLLUsage pDLLUsage;
static DLLStart pDLLStart;
static DLLStop pDLLStop;

//Pointers to dll.
static HINSTANCE hInstDll;

static const int maxArraySize = 5000;

using namespace std;

Settings::Settings()
{
    inputFile = new char[maxArraySize];
    resultFile = new char[maxArraySize];
    profileFile = new char[maxArraySize];

    inputFile[0] = resultFile[0] = profileFile[0] = '\0';
}

Settings :: ~Settings()
{
    delete inputFile;
    delete resultFile;
	delete profileFile;
}

static void AddNextChar(int &value, int source) // Convert char of input string to digit and add to 'value'
{
	value = value * 10 + ((int)source - (int)'0');	// digit transformation
}

// Parse input file into solver's structures.
int Settings::parseConfigFile(Solver* solver) 
{
    FILE *file;

    // Open the file to read from.
    if( fopen_s(&file, inputFile, "rb")) 
    {
        printf("Can't open configfile!\r\n");
        (pDLLUsage)();

        return -1;
    }

    char *str = new char[BUFFER_SIZE];
	int ch = 0;
	ch = getc(file);
	int cityCount = 0;
	while (feof(file) == 0 && ch != '\n')
	{
		if (!(ch == ' ' || ch == '\r'))
		{
			AddNextChar(cityCount, ch);
		}
		ch = getc(file);
	}
                
	int** distances = new int*[cityCount];
	int *buffer = new int[cityCount * cityCount];
	for (int i = 0; i < cityCount; i++)
	{
		int* row = buffer + i * cityCount;
		for (int j = 0; j < cityCount; j++)
		{
			row[j] = 0;								// zero (initial) value assignment
		}
		distances[i] = row;	// memory allotment for all rows
	}
    
	for (int i = 0; i < cityCount; i++)             // fill the array
    {
		int position = 0;                           // initialize the counter of tokens of current string  
		ch = getc(file);
		while ((feof(file) == 0) && (ch != '\n'))
		{
			if (ch == ' ')                 // condition of a new token start
			{
				position++;                         // change the array index
            }
			else if (ch == '\r') 
			{
				ch = getc(file);
				continue;
			}
			else
			{                              // convert from current token to int and put to the corresponding array cell
				if (ch == '-')             // edges where threre are no way (distance is equal to infinity)
                {
					distances[i][position] = infinity;
                }
				else
				{
					AddNextChar(distances[i][position], ch);
                }
            }
			ch = getc(file);
		}
	}
	for (int i = 0; i < cityCount; i++)             // for the exception cases (de bene esse) we override the distances from point to the same to be equal infinity
    {
		distances[i][i] = infinity;
	}
	solver->cityCount = cityCount;
	solver->distances = distances;

    //Dispose input file.
    fclose(file);

    return 0;
}

// Init variables, parse cli params and input file.
int Settings::init(int argc, char** argv, Solver *slasolver) 
{
    
    // Load the dll into the address space
	//fix: C4706
    //if (!(hInstDll = LoadLibraryA("CliTools"))) 
    //{
	hInstDll = LoadLibraryA("CliTools");
	if(!hInstDll)
	{
        printf("Error while loading CliTools.dll.");

        return -1;
    }

    // Retrieve a pointer to the factory function
    pDLLParseArguments = 
        (DLLParseArguments) GetProcAddress(hInstDll, "parseArguments");

    pDLLUsage =
        (DLLUsage) GetProcAddress(hInstDll, "usage");

    pDLLStart = 
        (DLLStart) GetProcAddress(hInstDll, "start");

    pDLLStop = 
        (DLLStop) GetProcAddress(hInstDll, "stop");

    //Parse cli params.
    if ((pDLLParseArguments)(argc, argv, &inputFile, &profileFile,  &resultFile)) 
    {
        FreeLibrary(hInstDll); 
        return -1;
    }
    
    //Parse input file.
    if (parseConfigFile(slasolver)) 
    {
        FreeLibrary(hInstDll); 
        return -1;
    }

    //Write settings if it's needed.
    writeSettings(slasolver);	
    return 0;
}

// Start the time count.
void Settings::start() 
{
    (pDLLStart)();
}

// Problem results output.
void Settings::finish(Solver *solver)
{
    double time;
    (pDLLStop)(&time);

    //Release dll.
    FreeLibrary(hInstDll);//*/

    printf("\r\n");
    printf("Clock time (sec): %.8f \r\n", time);  
	printf("Total nodes:      %li \r\n", solver->totalNodes); 

    FILE* outputResult = 0;
    FILE* outputProfile = 0;

	if( fopen_s(&outputProfile, profileFile , "wb")) 
	{
		printf("Can't create profile file!\r\n");            
		fclose(outputProfile);
		return;
	}

	if( fopen_s(&outputResult, resultFile , "wb")) 
	{
		printf("Can't create result file!\r\n");   
		fclose(outputResult);
		return;
	}
        

    fprintf(outputProfile, "#Dwarfname:%s\r\n",DWARF_NAME);

    char tmpbuf[BUFFER_SIZE];
    _tzset();
    
    _strdate_s( tmpbuf, BUFFER_SIZE );
    fprintf(outputProfile, "#Time: %s ",tmpbuf);

    _strtime_s( tmpbuf, BUFFER_SIZE );
    fprintf(outputProfile, "%s \r\n",tmpbuf);

	fprintf(outputProfile, "#Dwarfname:%s\r\n", DWARF_NAME);

	fprintf(outputProfile, "#Matrix Size: %i\r\n", solver->cityCount);
	fprintf(outputProfile, "#Number of nodes: %il\r\n", solver->totalNodes);
	fprintf(outputProfile, "#Result time (sec): %.8f\r\n", time); 

	for (int i = 0; i < solver->cityCount; i++)
	{
		fprintf(outputResult, "Edge: (%i;%i)\r\n", i, solver->bestCities[i]);
	}

    fprintf(outputProfile, "#eof");//*/

    fclose(outputProfile);
    fclose(outputResult);
	
}

// Write settings.
void Settings::writeSettings(Solver *solver)
{
    // Write general settings.
    printf("Kernel settings summary : \r\n");
	printf("Dwarf name              : %s \r\n", DWARF_NAME);
    printf("Matrix Size             : %d \r\n", solver->cityCount);
	printf("Inputfile               : %s \r\n", inputFile);
	printf("Outputfile              : %s \r\n", resultFile);    
    printf("\r\n");   
}
